package net.xt.testthread.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 自定义锁AOP，防止多线程并发，每次只允许一个线程执行操作
 */
@Slf4j
@Component
@Aspect
@Order(1) //order越小越是最先执行，但更重要的是最先执行的最后结束
public class LockAOP {

    // 方式一：使用可重入锁
    private static Lock lock = new ReentrantLock(true); // 互斥锁 参数默认false，不公平锁
    // 方式二：使用信号量
//    private static Semaphore semaphore = new Semaphore(1);

    // 使用自定义注解ServiceLock
    @Pointcut("@annotation(net.xt.testthread.aop.ServiceLock)")
    public void lockAspect() {

    }

    @Around("lockAspect()")
    public Object around(ProceedingJoinPoint joinPoint) throws InterruptedException {
        // 加锁
        lock.lock();

        // 使用信号量
//        semaphore.acquire();

        Object obj = null;
        try {
            obj = joinPoint.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
            throw new RuntimeException();
        } finally {
            // 释放锁
            lock.unlock();

            // 释放信号量
//            semaphore.release();
        }

        return obj;
    }

}
